/*
 * Stutter web application
 * This web app detects repeated words in a line of text or across the lines of text.
 */
package stutter.web.client;

import java.io.IOException;
import stutter.web.shared.FieldVerifier;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Stutter_Web_App implements EntryPoint {
	/**
	 * The message displayed to the user when the server cannot be reached or
	 * returns an error.
	 */
	private static final String SERVER_ERROR = "An error occurred while "
			+ "attempting to contact the server. Please check your network "
			+ "connection and try again.";

	/**
	 * Create a remote service proxy to talk to the server-side Greeting service.
	 */
	private final GreetingServiceAsync greetingService = GWT
			.create(GreetingService.class);

	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
	    // Let's make an 80x50 text area to go along with the other two.
		final Button sendButton = new Button("Send");
		final TextBox tb = new TextBox();
	    final TextArea ta = new TextArea();
	    ta.setCharacterWidth(80);
	    ta.setVisibleLines(50);
	    final HTML errorLabel = new HTML();

	    sendButton.addStyleName("sendButton");
	    
	    // Add them to the root panel.
	    VerticalPanel panel = new VerticalPanel();
	    panel.add(sendButton);
	    //panel.add(tb);
	    panel.add(ta);
	    panel.add(errorLabel);
	    RootPanel.get().add(panel);
		RootPanel.get("sendButtonContainer").add(sendButton);
		RootPanel.get("errorLabelContainer").add(errorLabel);

		// Create a handler for the sendButton and nameField
		class MyHandler implements ClickHandler, KeyUpHandler {
			/**
			 * Fired when the user clicks on the sendButton.
			 */
			public void onClick(ClickEvent event) {
				sendNameToServer();
			}

			/**
			 * Fired when the user types in the nameField.
			 */
			public void onKeyUp(KeyUpEvent event) {
				if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
					sendNameToServer();
				}
			}

			/**
			 * Send the name from the nameField to the server and wait for a response.
			 */
			private void sendNameToServer() {
				// First, we validate the input.
				final String textToServer = ta.getText();
				if (!(textToServer.length() > 10)) {
					errorLabel.setText("Please enter at least four characters");
					return;
				}

				// Then, we send the input to the server.
				sendButton.setEnabled(false);
				try {
					String ar = Stutter(textToServer);
					errorLabel.setHTML(ar);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					errorLabel.setText(e.toString());
				}
				greetingService.greetServer(textToServer,
						new AsyncCallback<String>() {
							public void onFailure(Throwable caught) {
								errorLabel.setHTML("Failure");
							}

							public void onSuccess(String result) {
								try {
									String ar = Stutter(textToServer);
									errorLabel.setHTML(ar);
								} catch (IOException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
									errorLabel.setText(e.toString());
								}
							}
						});
			}
		}

		// Add a handler to send the name to the server
		MyHandler handler = new MyHandler();
		sendButton.addClickHandler(handler);
	}
	
	/**
	 * Detect stutter.
	 *
	 * @param arText the ar text
	 * @return the string[]
	 */
	public String[] DetectStutter(String[] arText)
	{
		if (arText.length > 0)
		{
			String [] arStutteredWordsAndLocations = new String[arText.length];
			int nIndexToStutteredWords = 0;
			String sStutterText = "";
			int lineNumber = 1;
			int wordCountTotal = 0;
			int wordCountLine = 0;
			// loop through array of words
			for (int nIndexToTextArray = 0; nIndexToTextArray < arText.length-1; nIndexToTextArray++)
			{
				if (arText[nIndexToTextArray]!= null && arText[nIndexToTextArray+1] != null)
				{
					wordCountTotal++;
					String lineNumberKey = "**Line**";
					boolean bSkipWordFlag = false;
					if (arText[nIndexToTextArray].indexOf(lineNumberKey) >= 0)
					{
						lineNumber = Integer.parseInt((arText[nIndexToTextArray].substring(lineNumberKey.length())))+1;
						bSkipWordFlag = true;
						wordCountLine = wordCountTotal;
					}
					//compare word n against word n+1
					if ((bSkipWordFlag == false && arText[nIndexToTextArray].equalsIgnoreCase(arText[nIndexToTextArray+1])))
					{
						//they are the same so report them
						sStutterText = "Repeated word on line " + lineNumber + " word number " + (wordCountTotal-wordCountLine)+ ": " + arText[nIndexToTextArray] + " <BR />\n";
						arStutteredWordsAndLocations[nIndexToStutteredWords++] = sStutterText;
					}
					//special case compares across lines
					else if ((bSkipWordFlag == true && arText[nIndexToTextArray-1].equalsIgnoreCase(arText[nIndexToTextArray+1])) ||
							(bSkipWordFlag == true && arText[nIndexToTextArray-2].equalsIgnoreCase(arText[nIndexToTextArray+1])))
					{
						//they are the same so report them
						sStutterText = "Repeated word on line " + lineNumber + " word number " + (wordCountTotal-wordCountLine)+ ": " + arText[nIndexToTextArray+1] + " <BR />\n";
						arStutteredWordsAndLocations[nIndexToStutteredWords++] = sStutterText;
					}
				}
			}
			return arStutteredWordsAndLocations;
		}
		else
		{
			return null;
		}
	}
	
	/**
	 * Are words equal.
	 *
	 * @param sWordOne the first word to compare
	 * @param sWordTwo the second word to compare
	 * @return true, if successful
	 */
	public boolean AreWordsEqual(String sWordOne, String sWordTwo)
	{
		return sWordOne.equalsIgnoreCase(sWordTwo);
	}
	
	/**
	 * Gets the tokens.
	 *
	 * @return the string[]
	 */
	public String[] GetTokens()
	{
		String [] arTokens = {"\0", "\n", "	", " ", "," , ".", "!", "-", "+", "=", ";", ":", "?", "&", "{", "}", "\\"};
		return arTokens;
	}
	
	/**
	 * Checks if is character token.
	 *
	 * @param cPossibleToken the c possible token
	 * @return true, if successful
	 */
	public boolean IsCharacterToken(char cPossibleToken)
	{
		String [] arTokens = GetTokens();
		int nCurrentTokenNum = 0;
		//loop through the list of tokens
		for (nCurrentTokenNum = 0; nCurrentTokenNum < arTokens.length; nCurrentTokenNum++)
		{
			//check to see if the character passed was a token in the array
			if (cPossibleToken == arTokens [nCurrentTokenNum].toCharArray()[0])
			{
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Copy string.
	 *
	 * @param sCopyFrom the string to copy from
	 * @param sCopyTo the string to copy to
	 * @return true, if successful
	 */
	public boolean CopyString(String sCopyFrom, String sCopyTo)
	{
		if (sCopyFrom.isEmpty())
		{
			return false;
		}
		sCopyTo = sCopyFrom;
		if (sCopyTo.equals(sCopyTo))
			return true;
		else
			return false;
	}
	
	/**
	 * String to array.
	 *
	 * @param wordString the word string
	 * @return the string[]
	 */
	public String[] stringToArray(String wordString) {
	    String [] result;
	    String [] lineBreakResult = wordString.split ("\n");
	    String line = "";
	    String multiLineIndex = "";
	    for (int iIndex = 0; iIndex < lineBreakResult.length; iIndex++)
	    {
	    	// get new line
	    	line = lineBreakResult[iIndex];
	    	// remove non-alphanumberic characters 
	    	line = line.replaceAll ("[^a-zA-Z0-9 ]", "");
			// Convert the input line to lower case
	    	line = line.toLowerCase();	
	    	// add special line code for processing
	    	multiLineIndex += line + " **Line**"+ (iIndex+1)+" ";
	    }
		// splits the line into words and puts in an array of strings
		result = multiLineIndex.split (" ");
		
	    return result;
	}
	
	/**
	 * Stutter.
	 *
	 * @param sInputText the s input text
	 * @return the string
	 * @throws IOException Signals that an I/O exception has occurred.
	 */
	public String Stutter(String sInputText) throws IOException
	{
		String[] arTokenizedContents = new String[(int)sInputText.length()];
		String[] arOutput = null;
		Scanner tokenize = null;
		try
		{
			String sLastWordOfLine = new String();
			if (!sInputText.isEmpty())
			{
				// seperate string into word array
				arTokenizedContents = stringToArray(sInputText);
				// look for repeated words in the word array
				arOutput = DetectStutter(arTokenizedContents);
			}
		}
		finally {
		  	}
		// return a string of the results
		String result = "I Found the following results: <br />";
		for (int i = 0; i < arOutput.length; i++)
		{
			if (arOutput[i] != null)
				result += arOutput[i] +"\r\n";
		}
		return result;
		}

	/**
	 * Process final tokens.
	 *
	 * @param next the next string in the array
	 * @return the string after processing
	 */
	public String ProcessFinalTokens(String next) {
		// TODO Auto-generated method stub
		String sUnTokenedString = "";
		boolean bToken = false;
		for (int nIndexToString = 0; nIndexToString < next.length(); nIndexToString++)
		{
			bToken = false;
			for (int nTokenIndex = 0; nTokenIndex < GetTokens().length; nTokenIndex++)
			{
				if (IsCharacterToken(next.toCharArray()[nIndexToString])==true)
				{
					//do nothing and ignore char
					bToken  = true;
					break;
				}
			}
			if (bToken)
			{
				//do nothing because it is a token
			}
			else
			{
				//not  a token character so add it to string 
				sUnTokenedString+= next.toCharArray()[nIndexToString];
			}
		}
		return sUnTokenedString; //return string - tokens
	}
	

}
